home *** CD-ROM | disk | FTP | other *** search
/ NeXTSTEP 3.3 (Developer)…68k, x86, SPARC, PA-RISC] / NeXTSTEP 3.3 Dev Intel.iso / NextDeveloper / Examples / DriverKit / SMC16 / SMC16_reloc.tproj / SMC16.m < prev    next >
Encoding:
Text File  |  1995-02-06  |  19.3 KB  |  961 lines

  1. /*
  2.  * Copyright (c) 1993 NeXT Computer, Inc.
  3.  *
  4.  * Driver class for SMC EtherCard Plus Elite16 adaptors.
  5.  *
  6.  * HISTORY
  7.  *
  8.  * 19 Apr 1993 
  9.  *    Added multicast & promiscuous mode support.
  10.  *
  11.  * 26 Jan 1993
  12.  *    Created.
  13.  */
  14.  
  15. #define MACH_USER_API    1
  16.  
  17. #import <driverkit/generalFuncs.h>
  18. #import <driverkit/IONetbufQueue.h>
  19.  
  20. #import "SMC16.h"
  21. #import "SMC16IOInline.h"
  22. #import "SMC16Private.h"
  23.  
  24. #import <kernserv/kern_server_types.h>
  25. #import <kernserv/prototypes.h>
  26. #import <kernserv/i386/spl.h>
  27.  
  28. @implementation SMC16
  29.  
  30. /*
  31.  * Private Instance Methods
  32.  */
  33.  
  34. /*
  35.  * _memAvail
  36.  * Returns the amount of onboard memory not currently in use.
  37.  * Never returns less than zero.
  38.  */
  39. - (SMC16_len_t)_memAvail
  40. {
  41.     int        available;
  42.     
  43.     available = (memtotal - memused);
  44.     
  45.     return ((SMC16_len_t) ((available < 0)? 0: available));
  46. }
  47.  
  48. /*
  49.  * _memRegion
  50.  * Returns the next available NIC_PAGE_SIZE chunk of onboard memory.
  51.  */
  52. - (SMC16_off_t)_memRegion:(SMC16_len_t)length
  53. {
  54.     if ([self _memAvail] < length)
  55.         IOPanic("SMC16: onboard memory exhausted");
  56.     
  57.     return ((SMC16_off_t) (memused / NIC_PAGE_SIZE));
  58. }
  59.  
  60. /*
  61.  * _memAlloc
  62.  * Allocates onboard memory in chunks of NIC_PAGE_SIZE 
  63.  */
  64. - (SMC16_off_t)_memAlloc:(SMC16_len_t)length
  65. {
  66.     SMC16_off_t    region;
  67.     
  68.     /*
  69.      * Round up to the next multiple of NIC_PAGE_SIZE
  70.      */
  71.     length = ((length + NIC_PAGE_SIZE - 1) & ~(NIC_PAGE_SIZE - 1));
  72.     
  73.     region = [self _memRegion:length];
  74.     
  75.     memused += length;
  76.     
  77.     return (region);
  78. }
  79.  
  80. /*
  81.  * _initializeHardware
  82.  * Resets the SMC adaptor.  Disables interrupts, resets the NIC, and
  83.  * configures the onboard memory.
  84.  */
  85. - (void)_initializeHardware
  86. {    
  87.     setIRQ(irq, YES, base);
  88.     
  89.     resetNIC(base);
  90.     
  91.     memtotal = setupRAM(membase, memsize, base);
  92.     memused = 0;
  93. }
  94.  
  95. /*
  96.  * _receiveInitialize
  97.  * Prepares the card for receive operations.  Allocates as many NIC_PAGE_SIZE
  98.  * buffers from the available onboard memory.
  99.  */
  100. - (void)_receiveInitialize
  101. {
  102.     SMC16_len_t        avail = [self _memAvail];
  103.     
  104.     rstart = [self _memAlloc:avail];
  105.     rstop = rstart + (avail / NIC_PAGE_SIZE);
  106.  
  107.     /*
  108.      * Setup the receive ring
  109.      */    
  110.     put_rstart_reg(rstart, base); put_rstop_reg(rstop, base);
  111.     
  112.     /*
  113.      * Reset the boundary buffer pointer
  114.      */    
  115.     put_bound_reg(rstart, base);
  116.     
  117.     rnext = rstart + 1;
  118.     
  119.     /*
  120.      * Reset the current buffer pointer    
  121.      */    
  122.     (void)sel_reg_page(REG_PAGE1, base);
  123.     put_curr_reg(rnext, base);
  124.     (void)sel_reg_page(REG_PAGE0, base);
  125. }
  126.  
  127. /*
  128.  * _transmitInitialize
  129.  * Prepares for transmit operations.  We use 1 transmit buffer of maximum
  130.  * size.
  131.  */
  132. - (void)_transmitInitialize
  133. {
  134.     tstart = [self _memAlloc:ETHERMAXPACKET];
  135. }
  136.  
  137. /*
  138.  * _initializeSoftware
  139.  * Prepare the adaptor for network operations and start them.
  140.  */
  141. - (void)_initializeSoftware
  142. {
  143.     setStationAddress(&myAddress, base);
  144.     
  145.     [self _transmitInitialize]; 
  146.     [self _receiveInitialize];
  147.         
  148.     startNIC(base, rconsave);
  149. }
  150.  
  151. /*
  152.  * _receiveInterruptOccurred
  153.  * This method handles the process of moving received frames from 
  154.  * onboard adaptor memory to netbufs and handing them up to the network
  155.  * object.
  156.  */
  157. - (void)_receiveInterruptOccurred
  158. {
  159.     nic_recv_hdr_t    *rhdr;
  160.     netbuf_t        pkt;
  161.     int            pkt_len, pre_wrap_len;
  162.     void         *pkt_data = NULL;
  163.  
  164. #ifdef DEBUG
  165.  
  166.     /*
  167.      * Change this to 1 to be inundated with messages.
  168.      */
  169.     boolean_t    SMC16_recvTrace = 0;
  170.  
  171. #endif DEBUG
  172.  
  173.     
  174.     /*
  175.      * Grab buffers until we point to the next available one.
  176.      */
  177.     while (rnext != getCurrentBuffer(base)) {
  178.  
  179.     /*
  180.      * Point to the receive header in this buffer.
  181.      */
  182.     rhdr = (nic_recv_hdr_t *)nic_page_addr(rnext,membase);
  183.  
  184. #ifdef DEBUG
  185.     if (SMC16_recvTrace) {
  186.         IOLog("[rstat %02x next %02x len %03x rnext "
  187.             "%02x bound %02x curr %02x]\n",
  188.             *(unsigned char *)&rhdr->rstat, 
  189.         rhdr->next, rhdr->len, rnext, 
  190.         get_bound_reg(base), getCurrentBuffer(base));
  191.     }
  192. #endif DEBUG
  193.     
  194.     
  195.     /*
  196.      * Display a somewhat cryptic message if the prx bit is set.
  197.      */
  198.     if (!rhdr->rstat.prx) {
  199.         IOLog("rhdr1 rstat %02x next %02x len %x\n", 
  200.             *(unsigned char *)&rhdr->rstat, rhdr->next, rhdr->len);
  201.         [network incrementInputErrors];
  202.         rnext = rhdr->next; 
  203.         continue;
  204.     }
  205.     
  206.     /*
  207.      * Display a slightly different, equally cryptic message 
  208.      * if the pointer to the next buffer in this header is outside
  209.      * the range configured buffers.  If this is the case, force a
  210.      * reset by invoking -timeoutOccurred.
  211.      */
  212.     if (rhdr->next >= rstop || rhdr->next < rstart) {
  213.         IOLog("rhdr2 rstat %02x next %02x len %x\n", 
  214.             *(unsigned char *)&rhdr->rstat, rhdr->next, rhdr->len);
  215.         [network incrementInputErrors];
  216.         [self timeoutOccurred]; 
  217.         return;
  218.     }
  219.  
  220.     /*
  221.      * Get the overall packet length and the length between
  222.      * the start of the packet and the end of onboard memory.
  223.      * Any packet data beyond that will wrap back to the start
  224.      * of onboard memory.
  225.      */
  226.     pkt_len = rhdr->len - ETHERCRC;
  227.     pre_wrap_len =    nic_page_addr(rstop,membase) -
  228.             nic_page_addr(rnext,membase) -
  229.             sizeof (*rhdr);
  230.  
  231.     /*
  232.      * If the packet length looks reasonable, allocate a net buffer
  233.      * for it and establish a pointer to the data in that net buffer.
  234.      */
  235.     if (pkt_len >= (ETHERMINPACKET - ETHERCRC) && 
  236.         pkt_len <= ETHERMAXPACKET) {
  237.         pkt = nb_alloc(pkt_len);
  238.         if (pkt)
  239.             pkt_data = nb_map(pkt);
  240.     }
  241.     else {
  242.         [network incrementInputErrors];
  243.         pkt = 0;
  244.     }
  245.         
  246.     /*
  247.      * If none of the packet wraps around the ring, just
  248.      * copy it into the netbuf.
  249.      */
  250.     if (pkt_len <= pre_wrap_len) {
  251.         if (pkt)
  252.         IOCopyMemory(
  253.             (void *)nic_page_addr(rnext,membase) + sizeof (*rhdr),
  254.             pkt_data,
  255.             pkt_len,
  256.             sizeof(short));
  257.     /*
  258.      * Otherwise, copy up to the end of memory, then copy the remaining
  259.      * portion from the start of memory.
  260.      */
  261.     }
  262.     else {
  263.         if (pkt) {
  264.         IOCopyMemory(
  265.             (void *)nic_page_addr(rnext,membase) + sizeof (*rhdr),
  266.             pkt_data,
  267.             pre_wrap_len,
  268.             sizeof(short));
  269.         IOCopyMemory(
  270.             (void *)nic_page_addr(rstart,membase),
  271.             pkt_data + pre_wrap_len,
  272.             pkt_len - pre_wrap_len,
  273.             sizeof(short));
  274.         }
  275.     }
  276.     
  277.     /*
  278.      * Increment the ring buffer pointers.
  279.      */
  280.     rnext = rhdr->next;
  281.     if ((rnext - 1) >= rstart)
  282.         put_bound_reg(rnext - 1, base);
  283.     else
  284.         put_bound_reg(rstop - 1, base);
  285.  
  286.     /*
  287.      * We only pass packets upward if they pass thru multicast filter.
  288.      */
  289.     if(pkt) {
  290.           if(rconsave.prom == 0 && [super 
  291.             isUnwantedMulticastPacket:(ether_header_t *)nb_map(pkt)]) {
  292.         nb_free(pkt);
  293.         } 
  294.         else {
  295.         
  296.             [network handleInputPacket:pkt extra:0];
  297.  
  298.         } 
  299.     }
  300.     }
  301.  
  302. }
  303.  
  304. /*
  305.  * _receiveOverwriteOccurred
  306.  * Called when the adaptor tells us that we haven't fetched frames from
  307.  * onboard memory fast enough, so it's overwritten an old frame with a new
  308.  * one.  Oh well...
  309.  */
  310. - (void)_receiveOverwriteOccurred
  311. {
  312. #ifdef DEBUG
  313.     IOLog("overwrite bound %02x curr %02x rnext %02x\n", get_bound_reg(base), getCurrentBuffer(base), rnext);
  314.     [network incrementInputErrors];
  315. #endif DEBUG
  316. }
  317.  
  318. /*
  319.  * _transmitInterruptOccurred
  320.  * Called when the adaptor indicated a transmit operation is complete.  Check
  321.  * tstat register and increment the appropriate counters.  Clear the
  322.  * timeout we set when we initiated the transmit and clear the transmitActive
  323.  * flag.  Finally, if there are any outgoing packets in the queue, send the
  324.  * next one.
  325.  */
  326. - (void)_transmitInterruptOccurred
  327. {
  328.     nic_tstat_reg_t    tstat_reg;
  329.     netbuf_t        pkt;
  330.  
  331.     if (transmitActive) {
  332.         tstat_reg = get_tstat_reg(base);
  333.     
  334.     /*
  335.      * Always check transmit status (if available) here.  On a
  336.      * transmit error, increment statistics and reset the
  337.      * adaptor if necessary (not for SMC).  NEVER TRY TO 
  338.      * RETRANSMIT A PACKET.  Leave this up to higher level
  339.      * software, which should insure reliability when
  340.      * it's needed.
  341.      */
  342.     if (tstat_reg.ptx)
  343.         [network incrementOutputPackets];
  344.     else
  345.         [network incrementOutputErrors];
  346.         
  347.     if (tstat_reg.abort || tstat_reg.twc)
  348.         [network incrementCollisions];
  349.     
  350.     [self clearTimeout];    
  351.     transmitActive = NO;
  352.     }
  353.     
  354.     if (pkt = [transmitQueue dequeue])
  355.         [self transmit:pkt];
  356. }
  357.  
  358. /*
  359.  * Public Factory Methods
  360.  */
  361.  
  362. + (BOOL)probe:(IODeviceDescription *)devDesc
  363. {
  364.     SMC16        *dev = [self alloc];
  365.     IOEISADeviceDescription
  366.             *deviceDescription = (IOEISADeviceDescription *)devDesc;
  367.     IORange        *io;
  368.  
  369.     if (dev == nil)
  370.         return NO;
  371.     
  372.     /* 
  373.      * Valid configuration?
  374.      */
  375.     if (    [deviceDescription numPortRanges] < 1
  376.         ||
  377.             [deviceDescription numMemoryRanges] < 1
  378.         ||
  379.             [deviceDescription numInterrupts] < 1) {
  380.         [dev free]; 
  381.     return NO;
  382.     }
  383.     
  384.     /*
  385.      * Make sure we're configured for 16K (even though we can only use 8)
  386.      */
  387.     io = [deviceDescription memoryRangeList];
  388.     if (io->size < 16*1024) {
  389.         [dev free]; 
  390.     return NO;
  391.     }
  392.     
  393.     /*
  394.      * More configuration validation
  395.      */
  396.     io = [deviceDescription portRangeList];
  397.     if (io->size < 16) {
  398.     [dev free]; 
  399.     return NO;
  400.     }
  401.  
  402.     /* 
  403.      * Configuration checks out so let's actually probe for hardware.
  404.      */
  405.     if (!checksumLAR(io->start)) {
  406.         IOLog("SMC16: Adaptor not present or invalid EEROM checksum.\n");
  407.     [dev free]; 
  408.     return NO;
  409.     }
  410.     
  411.     if (!checkBoardRev(io->start)) {
  412.         IOLog("SMC16: Unsupported board revision.\n");
  413.     [dev free]; 
  414.     return NO;
  415.     }
  416.     
  417.     return [dev initFromDeviceDescription:devDesc] != nil;
  418. }
  419.  
  420. /*
  421.  * Public Instance Methods
  422.  */
  423.  
  424. - initFromDeviceDescription:(IODeviceDescription *)devDesc
  425. {
  426.     IOEISADeviceDescription
  427.             *deviceDescription = (IOEISADeviceDescription *)devDesc;
  428.     IORange        *io;
  429.  
  430.     if ([super initFromDeviceDescription:devDesc] == nil) 
  431.         return nil;
  432.     
  433.     /* 
  434.      * Initialize ivars
  435.      */
  436.     irq = [deviceDescription interrupt];
  437.     
  438.     io = [deviceDescription portRangeList];
  439.     base = io->start;
  440.     
  441.     io = [deviceDescription memoryRangeList];
  442.     membase = io->start;    
  443.     memsize = io->size;
  444.  
  445.     /*
  446.      * Broadcasts should be enabled
  447.      */
  448.     rconsave.broad = 1;
  449.  
  450.     /*
  451.      * Reset the adaptor, but don't enable yet.  We'll receive 
  452.      * -resetAndEnable:YES as a side effect of calling
  453.      * -attachToNetworkWithAddress:
  454.      */
  455.     [self resetAndEnable:NO];    
  456.     
  457.     IOLog("SMC16 at port %x irq %d\n",base, irq);
  458.         
  459.     transmitQueue = [[IONetbufQueue alloc] initWithMaxCount:32];
  460.     
  461.     network = [super attachToNetworkWithAddress:myAddress];
  462.     return self;        
  463. }
  464.  
  465. - free
  466. {
  467.     [transmitQueue free];
  468.     
  469.     return [super free];
  470. }
  471.  
  472. - (IOReturn)enableAllInterrupts
  473. {
  474.     unmaskInterrupts(base);
  475.  
  476.     setIRQ(irq, YES, base);
  477.     
  478.     return [super enableAllInterrupts];
  479. }
  480.  
  481. - (void)disableAllInterrupts
  482. {
  483.     setIRQ(irq, NO, base);
  484.     
  485.     [super disableAllInterrupts];
  486. }
  487.  
  488. - (BOOL)resetAndEnable:(BOOL)enable
  489. {
  490.     [self disableAllInterrupts];
  491.    
  492.     transmitActive = NO;
  493.     
  494.     [self _initializeHardware];
  495.     
  496.     getStationAddress(&myAddress, base);
  497.     
  498.     [self _initializeSoftware];
  499.     
  500.     if (enable && [self enableAllInterrupts] != IO_R_SUCCESS) {
  501.     [self setRunning:NO];
  502.         return NO;
  503.     }
  504.     
  505.     [self setRunning:enable];
  506.     return YES;
  507. }
  508.  
  509. - (void)timeoutOccurred
  510. {
  511.     netbuf_t    pkt = NULL;
  512.     
  513.     if ([self isRunning]) {
  514.         if ([self resetAndEnable:YES]) {
  515.  
  516.         if (pkt = [transmitQueue dequeue])
  517.         [self transmit:pkt];
  518.     }
  519.     }
  520.     /*
  521.      * Value of [self isRunning] may have been modified by
  522.      * resetAndEnable:
  523.      */
  524.     if (![self isRunning]) {    
  525.     /*
  526.      * Free any packets in the queue since we're not running.
  527.      */
  528.         if ([transmitQueue count]) {
  529.         transmitActive = NO;
  530.         while (pkt = [transmitQueue dequeue])
  531.         nb_free(pkt);
  532.     }
  533.     }
  534. }
  535.  
  536. /* 
  537.  * Called by our IOThread when it receives a message signifying
  538.  * an interrupt.  We check the istat register and vector off
  539.  * to the appropriate handler routines.
  540.  */
  541. - (void)interruptOccurred
  542. {
  543.     nic_istat_reg_t    istat_reg;
  544.     
  545.     istat_reg = get_istat_reg(base);
  546.     put_istat_reg(istat_reg, base);
  547.     
  548.     if (istat_reg.ovw)
  549.         [self _receiveOverwriteOccurred];
  550.     
  551.     if (istat_reg.prx)
  552.         [self _receiveInterruptOccurred];
  553.         
  554.     if (istat_reg.ptx || istat_reg.txe)
  555.         [self _transmitInterruptOccurred];
  556. }
  557.  
  558.  
  559. /*
  560.  * Enable promiscuous mode (invoked by superclass).
  561.  */
  562. - (BOOL)enablePromiscuousMode
  563. {
  564.     int     old_page = sel_reg_page(REG_PAGE0, base);
  565.  
  566.     rconsave.prom = 1;
  567.     put_rcon_reg(rconsave, base);
  568.     sel_reg_page(old_page, base);
  569.  
  570.     return YES;
  571. }
  572.  
  573. /*
  574.  * Disable promiscuous mode (invoked by superclass).
  575.  */
  576. - (void)disablePromiscuousMode
  577. {
  578.    int     old_page = sel_reg_page(REG_PAGE0, base);
  579.  
  580.     rconsave.prom = 0;
  581.     put_rcon_reg(rconsave, base);
  582.     sel_reg_page(old_page, base);
  583.  
  584. }
  585.  
  586.  
  587. - (BOOL)enableMulticastMode
  588. {
  589.     int     old_page = sel_reg_page(REG_PAGE0, base);
  590.  
  591.     rconsave.group = 1;
  592.     put_rcon_reg(rconsave, base);
  593.     sel_reg_page(old_page, base);
  594.  
  595.     return YES;
  596. }
  597.  
  598. - (void)disableMulticastMode
  599. {
  600.     int     old_page = sel_reg_page(REG_PAGE0, base);
  601.  
  602.     rconsave.group = 0;
  603.     put_rcon_reg(rconsave, base);
  604.     sel_reg_page(old_page, base);
  605.  
  606. }
  607.  
  608. - (void)transmit:(netbuf_t)pkt
  609. {
  610.     int            pkt_len;
  611.  
  612.     /*
  613.      * If we're already transmitting, just queue up the packet.
  614.      */
  615.     if (transmitActive)
  616.         [transmitQueue enqueue:pkt];
  617.     else {
  618.      
  619.     /*
  620.      * We execute a softare loopback since this adaptor doesn't
  621.      * deal with this in hardware.
  622.      */
  623.     [self performLoopback:pkt];     
  624.         
  625.     /*
  626.      * Copy the packet into our transmit buffer, then free it.
  627.      */
  628.     pkt_len = nb_size(pkt);
  629.     IOCopyMemory(
  630.         nb_map(pkt),
  631.         (void *)nic_page_addr(tstart,membase),
  632.         pkt_len,
  633.         sizeof(short));
  634.     
  635.     /*
  636.      * Once the packet is copied out to the adaptor's onboard RAM,
  637.      * always free the packet.  DON'T SAVE A REFERENCE FOR 
  638.      * RETRANSMISSION PURPOSES.  Retransmission should be handled
  639.      * at the higher levels.  
  640.      */
  641.     nb_free(pkt);
  642.     
  643.     /*
  644.      * Setup up and initiate the transmit operation
  645.      */
  646.     put_tcnt_reg(pkt_len, base);
  647.     put_tstart_reg(tstart, base);
  648.     startTransmit(base);
  649.     
  650.     /*
  651.      * Start a timer whose expiration will call -timeoutOccurred, then
  652.      * set the transmitActive flag so we don't step on this operation.
  653.      */
  654.     [self setRelativeTimeout:3000];
  655.     transmitActive = YES;
  656.     }
  657. }
  658.  
  659.  
  660. @end
  661.  
  662. /*
  663.  * Private Functions
  664.  */
  665.  
  666. static BOOL
  667. checksumLAR(
  668.     IOEISAPortAddress    base
  669. )
  670. {
  671.     IOEISAPortAddress    offset;
  672.     unsigned char    sum = 0;
  673.     
  674.     for (offset = BIC_LAR_OFF; offset <= BIC_LAR_CKSUM_OFF; offset++)
  675.         sum += inb(base + SMC16_BIC_OFF + offset);
  676.     
  677.     return (sum == 0xff);
  678. }
  679.  
  680. static void
  681. getStationAddress(
  682.     enet_addr_t        *ea,
  683.     IOEISAPortAddress    base
  684. )
  685. {
  686.     int            i;
  687.     unsigned char    *enaddr = (unsigned char *)ea;
  688.     
  689.     for (i = 0; i < sizeof (*ea); i++)
  690.         *(enaddr + i) = inb(base + SMC16_BIC_OFF + BIC_LAR_OFF + i);
  691. }
  692.  
  693. static void
  694. setStationAddress(
  695.     enet_addr_t        *ea,
  696.     IOEISAPortAddress    base
  697. )
  698. {
  699.     int            i, old_page;
  700.     unsigned char    *enaddr = (unsigned char *)ea;
  701.     
  702.     old_page = sel_reg_page(REG_PAGE1, base);
  703.     
  704.     for (i = 0; i < sizeof (*ea); i++)
  705.         outb(base + SMC16_NIC_OFF + NIC_STA_REG_OFF + i, *(enaddr + i));
  706.     
  707.     (void)sel_reg_page(old_page, base);
  708. }
  709.  
  710. static BOOL
  711. checkBoardRev(
  712.     IOEISAPortAddress    base
  713. )
  714. {
  715.     unsigned int    bid;
  716.     
  717.     bid = get_bid(base);
  718.     
  719.     if (SMC16_REV(bid) < 2)
  720.         return NO;
  721.     
  722.     return YES;
  723. }
  724.  
  725. static void
  726. resetNIC(
  727.     IOEISAPortAddress    base
  728. )
  729. {
  730.     bic_msr_t        msr = { 0 };
  731.     nic_istat_reg_t    istat_reg;
  732.  
  733.     /*
  734.      * Perform HW Reset of NIC    
  735.      */    
  736.     msr.rst = 1;    put_msr(msr, base);
  737.     IODelay(500);
  738.     msr.rst = 0;    put_msr(msr, base);
  739.  
  740.     /*
  741.      * Wait for NIC to enter stopped state    
  742.      */    
  743.     do {
  744.     istat_reg = get_istat_reg(base);
  745.     } while (istat_reg.rst == 0);
  746. }
  747.  
  748. static SMC16_len_t
  749. setupRAM(
  750.     vm_offset_t        addr,
  751.     vm_size_t        size,
  752.     IOEISAPortAddress    base
  753. )
  754. {
  755.     SMC16_len_t        total;
  756.     SMC16_off_t        block_addr;
  757.     bic_laar_t        laar;
  758.     bic_msr_t        msr;
  759. #ifdef SIXTEEN_BIT_MODE
  760.     bic_icr_t        icr;
  761. #endif SIXTEEN_BIT_MODE
  762.     union {
  763.     struct {
  764.         unsigned int        :13,
  765.                 madr    :6,
  766.                 ladr    :5,
  767.                         :8;
  768.     } bic_addr;
  769.     struct {
  770.        unsigned int            :16,
  771.                    block    :8,
  772.                         :8;
  773.     } nic_addr;
  774.     unsigned int    address;
  775.     } _mconv;
  776.  
  777. /*
  778.  * NOTE:  We cannot put the card into 16-bit (and therefore 16K) mode because
  779.  * the bus interface chip will behave as though a full 64K is mapped, even
  780.  * though only 16K exists on the board.  Needless to say this causes problems,
  781.  * whether something else is mapped into the top 3/4 of that 64K or not.
  782.  * Unless the hardware changes, we're limited to using 8K of onboard memory
  783.  * and 8-bit transfer mode.
  784.  */     
  785.  
  786. #ifdef SIXTEEN_BIT_MODE
  787.     icr = get_icr(base);
  788.  
  789.     total = (icr.msz ? 16 : 64) * 1024;
  790.  
  791.     if (total > 16 * 1024)
  792.     total = 16 * 1024;
  793. #else // SIXTEEN_BIT_MODE
  794.     total = 8 * 1024;
  795. #endif SIXTEEN_BIT_MODE
  796.     
  797.     if (total > size)
  798.     total = size;
  799.  
  800. #ifdef DEBUG
  801.     IOLog("SMC16: using %d bytes of onboard memory\n",total);
  802. #endif DEBUG
  803.  
  804.     _mconv.address = addr;
  805.  
  806.     laar = get_laar(base);
  807. #ifdef SIXTEEN_BIT_MODE        
  808.     laar.zws16 = TRUE;
  809.     laar.l16en = TRUE;
  810.     laar.m16en = TRUE;
  811. #endif SIXTEEN_BIT_MODE
  812.     laar.ladr = _mconv.bic_addr.ladr;
  813.     put_laar(laar, base);
  814.     
  815.     msr = get_msr(base);
  816.     msr.madr = _mconv.bic_addr.madr;
  817.     msr.menb = TRUE;
  818.     put_msr(msr, base);
  819.  
  820.     block_addr = _mconv.nic_addr.block;
  821.     put_block_reg(block_addr, base);
  822.  
  823.     return (total);
  824. }
  825.     
  826. static void
  827. startNIC(
  828.     IOEISAPortAddress    base,
  829.     nic_rcon_reg_t    rcon_reg
  830. )
  831. {
  832.     nic_cmd_reg_t    cmd_reg = { 0 };
  833.     nic_enh_reg_t    enh_reg = { 0 };
  834.     nic_dcon_reg_t    dcon_reg = { 0 };
  835.     nic_tcon_reg_t    tcon_reg = { 0 };
  836.     nic_istat_reg_t    istat_reg;
  837.  
  838.     enh_reg.slot = NIC_SLOT_512_BIT;
  839.     enh_reg.wait = 0;
  840.     put_enh_reg(enh_reg, base);
  841.  
  842.     dcon_reg.bsize = NIC_DMA_BURST_8b;
  843. #ifdef SIXTEEN_BIT_MODE
  844.     dcon_reg.bus16 = TRUE;
  845. #endif SIXTEEN_BIT_MODE
  846.     put_dcon_reg(dcon_reg, base);
  847.     
  848.     put_tcon_reg(tcon_reg, base);
  849.     
  850.     istat_reg = get_istat_reg(base);
  851.     put_istat_reg(istat_reg, base);
  852.     
  853.     cmd_reg.sta = 1;
  854.     put_cmd_reg(cmd_reg, base);
  855.     
  856.     put_rcon_reg(rcon_reg, base);
  857. }
  858.  
  859. static void
  860. unmaskInterrupts(
  861.     IOEISAPortAddress    base
  862. )
  863. {
  864.     nic_imask_reg_t    imask_reg = { 0 };
  865.  
  866.     /*
  867.      * Receive conditions
  868.      */    
  869.     imask_reg.prxe = imask_reg.rxee = imask_reg.ovwe = TRUE;
  870.     
  871.     /*
  872.      * Transmit conditions
  873.      */    
  874.     imask_reg.ptxe = imask_reg.txee = TRUE;
  875.     
  876.     put_imask_reg(imask_reg, base);
  877. }
  878.  
  879. static SMC16_off_t
  880. getCurrentBuffer(
  881.     IOEISAPortAddress    base
  882. )
  883. {
  884.     SMC16_off_t        curr;
  885.     int            old_page;
  886.     
  887.     old_page = sel_reg_page(REG_PAGE1, base);
  888.     curr = get_curr_reg(base);
  889.     if (old_page != REG_PAGE1)
  890.         sel_reg_page(old_page, base);
  891.     
  892.     return (curr);
  893. }
  894.  
  895. static void
  896. startTransmit(
  897.     IOEISAPortAddress    base
  898. )
  899. {
  900.     nic_cmd_reg_t    cmd_reg = { 0 };
  901.     
  902.     cmd_reg.txp = 1;
  903.     cmd_reg.sta = 1;
  904.     put_cmd_reg(cmd_reg, base);
  905. }
  906.  
  907. static void
  908. setIRQ(
  909.     int            irq,
  910.     BOOL        enable,
  911.     IOEISAPortAddress    base
  912. )
  913. {
  914.     bic_irr_t        irr;
  915.     bic_icr_t        icr;
  916.     static char        _irx_map[16] = {    -1,
  917.                         -1,
  918.                         -1,
  919.                         BIC_IRX_3,
  920.                         BIC_IRX_4,
  921.                         BIC_IRX_5,
  922.                         -1,
  923.                         BIC_IRX_7,
  924.                         -1,
  925.                         BIC_IRX_9,
  926.                         BIC_IRX_10,
  927.                         BIC_IRX_11,
  928.                         -1,
  929.                         -1,
  930.                         -1,
  931.                         BIC_IRX_15 };
  932.     static char        _ir2_map[16] = {    -1,
  933.                         -1,
  934.                         -1,
  935.                         ICR_IR2_3,
  936.                         ICR_IR2_4,
  937.                         ICR_IR2_5,
  938.                         -1,
  939.                         ICR_IR2_7,
  940.                         -1,
  941.                         ICR_IR2_9,
  942.                         ICR_IR2_10,
  943.                         ICR_IR2_11,
  944.                         -1,
  945.                         -1,
  946.                         -1,
  947.                         ICR_IR2_15 };
  948.  
  949.     irr = get_irr(base);
  950.     irr.irx = _irx_map[irq]; 
  951.     irr.ien = FALSE;
  952.     put_irr(irr, base);
  953.  
  954.     icr = get_icr(base);
  955.     icr.ir2 = _ir2_map[irq];
  956.     put_icr(icr, base);
  957.     
  958.     irr.ien = enable;
  959.     put_irr(irr, base);    
  960. }
  961.